﻿#include "OperCSVPostDataImport.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include "FITK_Kernel/FITKAppFramework/FITKComponents.h"
#include "FITK_Kernel/FITKCore/FITKAbstractDataObject.h"
#include "FITK_Kernel/FITKCore/FITKThreadPool.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include "OperatorsInterface/GraphEventOperator.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractJunction.h"
#include "FITK_Component/FITKAcousticsPostData/FITKAcousticsPostData.h"
#include "FITK_Component/FITKAcousticsPostData/FITKAcousticsCSVParameter.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKGlobalFrequencyDomain.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include <QFile>
#include <QFileDialog>
#include <QTextStream>

namespace ModelOper
{

    bool OperCSVPostDataImport::execGUI()
    {
        //清理参数数据
        this->clearArgs();
        //主界面
        QWidget* mainWindow = FITKAPP->getGlobalData()->getMainWindow();
        if (!mainWindow || !_emitter) return false;
        //获取工作目录
        QString workDir;
        AppFrame::FITKAppSettings* settings = FITKAPP->getAppSettings();
        if (settings)
            workDir = settings->getWorkingDir();

        //获取并设置导入类型,创建导入窗口
        QString actionName = _emitter->objectName();
        QString title, filter;
        if (actionName == "actionCSVResult")
        {
            this->setArgs("FileType", "CSV");
            title = tr("Import CSV File");
            filter = "CSV(*.csv)";
        }
        QFileDialog dialog(mainWindow, title, workDir, filter);
        dialog.setAcceptMode(QFileDialog::AcceptOpen);  //打开模式
        dialog.show();
        //阻塞，否则键盘事件处理会出问题
        bool accept = false;
        QEventLoop loop;
        connect(&dialog, &QFileDialog::accepted, [&] {loop.quit(); accept = true;  });
        connect(&dialog, &QFileDialog::rejected, [&] {loop.quit(); accept = false;  });
        loop.exec();
        if (!accept) return false;
        //获取选择的文件名称
        QStringList files = dialog.selectedFiles();
        if (files.isEmpty()) return false;
        QString fileName = files.at(0);
        if (fileName.isEmpty())
            return false;
        //设置读取的文件路径
        this->setArgs("FileName", fileName);
        return true;
    }

    bool OperCSVPostDataImport::execProfession()
    {
        QString type;
        if (!this->argValue<QString>("FileType", type)) return false;
        bool okProfession = false;
        if (type == "CSV")
            okProfession = this->importCSVResult();
        return okProfession;
    }
    
    bool OperCSVPostDataImport::importCSVResult()
    {
        //导入文件名
        QString fileName;
        if (!this->argValue<QString>("FileName", fileName) || fileName.isEmpty()) return false;
        this->clearData();
        //创建读取线程
        ModelOper::ImportCSVFileThread* thread = new ModelOper::ImportCSVFileThread(this);
        thread->setFileName(fileName);
        //获取线程池
        Core::FITKThreadPool* pool = Core::FITKThreadPool::getInstance();
        if (pool == nullptr)return false;
        //等待线程结束
        pool->wait();
        pool->execTask(thread);
        //保存执行的脚本
        QString scr = QString("Global.Files.ImportCSVFile('%1')").arg(fileName);
        this->saveScript(scr);
        return true;
    }

    void OperCSVPostDataImport::clearData()
    {
        Acoustics::FITKAcousticsPostData* postData =
            FITKAPP->getGlobalData()->getPostData<Acoustics::FITKAcousticsPostData>();

        if (postData) postData->clearData();
    }

    ImportCSVFileThread::ImportCSVFileThread(Core::FITKActionOperator* oper) : _oper(oper)
    {
        //获取要存储的数据位置
        Acoustics::FITKAcousticsPostData* postData = FITKAPP->getGlobalData()->getPostData<Acoustics::FITKAcousticsPostData>();
        if (postData)
            _csvParaManager = postData->getCSVParameterManager();
        //获取管理器
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel)
        {
            _junctionManager = discModel->getJunctionManager();
            if (discModel->getSEAModel())
                _seaSubsysMgr = discModel->getSEAModel()->getSEASubSysManager();
        }
    }

    void ImportCSVFileThread::setFileName(QString fileName)
    {
        _fileName = fileName;
    }

    void ImportCSVFileThread::run()
    {
        if (_fileName.isEmpty()) return;
        //设置全局频率
        this->setGlobalFrequency();
        //获取csv文件路径
        QString fileName = _fileName;
        //打开csv文件
        QFile f(fileName);
        if (!f.exists() || !f.open(QIODevice::ReadOnly | QIODevice::Text))return;
        //打开文件流
        QTextStream stream(&f);
        while (!stream.atEnd())
        {
            //获取行数据
            QString line = stream.readLine();
            QStringList dataList = line.split(',');
            //读取数据
            this->readParameterData(dataList);
        }
        //关闭文件
        f.close();
        AppFrame::FITKMessageNormal(QObject::tr("Import CSV PostData Success! %1").arg(fileName));
    }

    void ImportCSVFileThread::setGlobalFrequency()
    {
        //获取全局频率范围
        Acoustics::FITKAcousticsPhysics* physicsData = FITKAPP->getGlobalData()->getPhysicsData<Acoustics::FITKAcousticsPhysics>();
        if (!physicsData || !_csvParaManager) return;
        Acoustics::FITKGlobalFrequencyDomain* freqDomain = physicsData->getFrequencyDomain();
        if (!freqDomain) return;
        //获取频率数据
        QList<double> freqList = freqDomain->getFrequenceList();
        std::vector<float> frequencyValue;
        for (QList<double>::iterator iter = freqList.begin(); iter != freqList.end(); ++iter)
            frequencyValue.push_back(*iter);
        _csvParaManager->setFrequency(frequencyValue);
    }

    void ImportCSVFileThread::readParameterData(QStringList dataList)
    {
        if (!_csvParaManager || dataList.size() < 3) return;
        //判断最后的值如果为空就移除
        if (dataList.last().isEmpty())
            dataList.removeLast();
        //读取名称,描述,类型
        QString name = dataList.at(0), describe = dataList.at(1), type = dataList.at(2).toLower();
        //获取参数类型
        Acoustics::FITKAcousticsCSVParameter::CSVParameterType paraType = Acoustics::FITKAcousticsCSVParameter::CSVParameterType::ParaNone;
        if (type == "modaldensity")
            paraType = Acoustics::FITKAcousticsCSVParameter::CSVParameterType::ModalDensity;
        else if (type == "lossfactor")
            paraType = Acoustics::FITKAcousticsCSVParameter::CSVParameterType::LossFactor;
        else if (type == "clf")
            paraType = Acoustics::FITKAcousticsCSVParameter::CSVParameterType::CLF;
        else if (type == "radiationefficiency")
            paraType = Acoustics::FITKAcousticsCSVParameter::CSVParameterType::RadiationEfficiency;
        if (paraType == Acoustics::FITKAcousticsCSVParameter::CSVParameterType::ParaNone) return;
        //获取数据对象ID
        int objID = this->getObjID(name, paraType);
        if (objID == -1) return;
        //获取后处理数值
        std::vector<float> paraValue;
        for (int i = 3; i < dataList.size(); ++i)
        {
            QString valueStr = dataList.at(i).trimmed();
            //获取数值
            bool ok = false;
            paraValue.push_back(valueStr.toFloat(&ok));
            if (!ok)return;
        }
        //获取参数数据
        Acoustics::FITKAcousticsCSVParameter* paraData = _csvParaManager->getCSVParameterData(objID, paraType);
        if (!paraData)
        {
            //创建参数数据
            paraData = new Acoustics::FITKAcousticsCSVParameter;
            _csvParaManager->appendDataObj(paraData);
        }
        //设置数据
        paraData->setCSVParameterType(paraType);
        paraData->setObjID(objID);
        paraData->insertParameterValue((describe.isEmpty() ? name : describe), paraValue);
    }

    int ImportCSVFileThread::getObjID(QString name, int paraType)
    {
        if (!_junctionManager || !_seaSubsysMgr) return -1;
        //获取对应名称的数据对象
        Core::FITKAbstractDataObject* obj = nullptr;
        if (paraType == Acoustics::FITKAcousticsCSVParameter::CSVParameterType::ModalDensity || paraType == Acoustics::FITKAcousticsCSVParameter::CSVParameterType::LossFactor)
            obj = _seaSubsysMgr->getDataObjectByName(name);
        else if (paraType == Acoustics::FITKAcousticsCSVParameter::CSVParameterType::CLF || paraType == Acoustics::FITKAcousticsCSVParameter::CSVParameterType::RadiationEfficiency)
            obj = _junctionManager->getDataObjectByName(name);
        if (!obj) return -1;
        //获取数据对象ID
        return obj->getDataObjectID();
    }

}

